package wangjg.coco.widgets;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

public class FileTreeBox extends Composite{
	private boolean dynamic = false;
	private String _root;
	private Tree tree;

	public FileTreeBox(Composite parent, int style) {
		this(parent, style, false, null);
	}

	public FileTreeBox(final Composite parent, int style, boolean dynamic, String root) {
		super(parent, style);
		tree = new Tree(this, SWT.CHECK|SWT.BORDER|SWT.V_SCROLL|SWT.H_SCROLL);
		tree.setBackground(new Color(this.getDisplay(),240,240,235));
		tree.setSize(300, 350);

		this.dynamic = dynamic;
		
//		this.addListener(SWT.Resize, new Listener () {
//		    public void handleEvent (Event e) {
//		    	Rectangle rect = FileTreeBox.this.getClientArea();
//		        tree.setSize(rect.width, rect.height);
//		      }
//		    });
	}
	
	public void load(String root){
		this._root = root;
		tree.removeAll();
		if(this._root!=null){
			this.makeTree(this._root);
		}
	}
	
	public Tree getTree() {
		return tree;
	}
	
	public void setTreeSize(int width, int height){
		this.tree.setSize(width, height);
	}

	public List<String> getSelectedFiles(){
		List<String> list = new ArrayList<String>();
		return this.getSelectedFiles(list, tree.getItems(), false);
	}
	
	public void setExpandedAll(final boolean expanded){
		recursive(tree.getItems(),new Handler(){
			public boolean handle(TreeItem item) {
				item.setExpanded(expanded);
				return true;
			}
		});
	}
	
	public void setCheckedAll(final boolean checked){
		recursive(tree.getItems(),new Handler(){
			public boolean handle(TreeItem item) {
				item.setChecked(checked);
				return true;
			}
		});
	}
	
	private void recursive(TreeItem[] items, Handler handler){
		for(TreeItem item:items){
			boolean goOn = handler.handle(item);
			if(goOn){
				recursive(item.getItems(), handler);
			}
		}
	}
	
	private List<String> getSelectedFiles(List<String> list, TreeItem[] items, boolean merge){
		for(TreeItem item:items){
			if(!item.getChecked()){
				continue;
			}
			File file = (File)item.getData();
			if(file==null){
				continue;
			}
			if(file.isFile()){
				list.add(file.getPath());
			}else if(!hasLoaded(item) || !this.hasCheckedChild(item)){
				list.add(file.getPath());
			}else{
				if(merge){
					list.add(file.getPath());
				}
				TreeItem[] subItems = item.getItems();
				getSelectedFiles(list, subItems, merge);
			}
		}
		return list;
	}

	private void makeTree(String root){
		Listener listener = new Listener(){
			public void handleEvent(Event event) {
				final TreeItem item = (TreeItem) event.item;
				if(event.type==SWT.Expand){
					setItemImage(item, "icons/folderopen.gif");
					if(dynamic){
						loadChildren(item);
					}
				}else if(event.type==SWT.Collapse){
					setItemImage(item, "icons/folder.gif");
				}else if(event.type==SWT.Selection){
					if(event.detail == SWT.CHECK){
						changeChildrenStatus(item);
						changeParentsStatus(item);	
					}
				}
			}
		};
		
		tree.addListener(SWT.Expand, listener);
		tree.addListener(SWT.Collapse, listener);
		tree.addListener(SWT.Selection, listener);
		
		File file = new File(root);
		this.makeSubItems(file, null, !dynamic);
	}
	
	protected void loadChildren(TreeItem item) {
		if(!hasLoaded(item)){
			File file = (File)item.getData();
			item.removeAll();
			for(File subfile:file.listFiles()){
				this.makeSubItems(subfile, item, false);
			}
		}
	}
	
	private boolean hasLoaded(TreeItem item){
		if(item.getItemCount()!=1){
			return true;
		}
		if(item.getItem(0).getData()!=null){
			return true;
		}
		return false;
	}
	
	public void makeSubItem(final File file) {
		this.makeSubItems(file, null, false);
	}
	
	private void makeSubItems(final File file, final TreeItem parent, final boolean recursive) {
		if(!file.canRead()){
			return;
		}
		TreeItem newItem;
		if(parent==null){
			newItem = new TreeItem(tree, SWT.NONE);
		}else{
			newItem = new TreeItem(parent, SWT.NONE);
			newItem.setChecked(parent.getChecked());
		}
		newItem.setText(file.getName());
		newItem.setData(file);
		if(file.isDirectory()){
			setItemImage(newItem, "icons/folder.gif");
			if(recursive){
				for(File subfile:file.listFiles()){
					this.makeSubItems(subfile, newItem, true);
				}
			}else if(file.list().length>0){
				TreeItem falgItem = new TreeItem(newItem, SWT.NONE);
				falgItem.setData(null);
			}
		}else{
			setItemImage(newItem, "icons/page.gif");
		}
	}
	
	private void setItemImage(TreeItem item, String path){
		try{
			ImageDescriptor temp = ImageDescriptor.createFromFile(this.getClass(), path);
			Image image = temp.createImage();
			item.setImage(image);
		}catch(Exception e){
			e.printStackTrace();
		}
	}

	private void changeChildrenStatus(final TreeItem item){
		if(item.getData()==null){
			return;
		}
		File file = (File)item.getData();
		if(!file.isDirectory()){
			return;
		}
		TreeItem[] items = item.getItems();
		for(TreeItem i:items){
			i.setChecked(item.getChecked());
			changeChildrenStatus(i);
		}
	}
	
	private void changeParentsStatus(final TreeItem item){
		TreeItem curItem = item.getParentItem();
		if(item.getChecked()){
			while(curItem!=null){
				curItem.setChecked(true);
				curItem = curItem.getParentItem();
			}
		}else{
			while(curItem!=null){
				if(this.hasCheckedChild(curItem)){
					break;
				}
				curItem.setChecked(false);
				curItem = curItem.getParentItem();
			}
		}
	}
	
	private boolean hasCheckedChild(TreeItem item){
		TreeItem[] items = item.getItems();
		for(TreeItem i:items){
			if(i.getChecked()){
				return true;
			}
		}
		return false;
	}

	static interface Handler{
		boolean handle(TreeItem item);
	}

	public static void main(String[] args) {
		Display display = new Display();
		Shell shell = new Shell(display);
		
		FileTreeBox fs = new FileTreeBox(shell, SWT.NONE);
		fs.load("D:\\temp\\debug");
		fs.getTree().setSize(400, 300);
		
		shell.setSize(500, 400);
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
		display.dispose();
	}

	public String getRoot() {
		return _root;
	}
}
